﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Drawing;
using System.IO;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    class ScreenCapturer
    {

        public ScreenCapturer()
        {
            /*
            double[,] s1 = detect(Image.FromFile(@"src\LRSS_e_tmp.png"));
            double[,] s2 = detect(Image.FromFile(@"src\LR\LRSS_e.png"));
            double[,] s3 = detect(Image.FromFile(@"src\LR\LRSS_112.png"));
            double d1 = HSVLib.ngdistance2(s1, s2);
            double d2 = HSVLib.ngdistance2(s1, s3);
            double d3 = HSVLib.ngdistance2(s3, s2);
             */
            /*
            DirectoryInfo d0 = new DirectoryInfo(@"trn");//C:\Users\Nostalgia\Desktop\src");
            FileInfo[] f0 = d0.GetFiles("*.png", SearchOption.AllDirectories);
            IEnumerable<FileInfo> fl0 = f0.Concat(d0.GetFiles("*.bmp", SearchOption.AllDirectories));
            */

            /*
            double[] s1 = detect(Image.FromFile(@"trn\SpellIcon_16.png"));
            double[] s2 = detect(Image.FromFile(@"src\DK\BDK_1.png"));
            double[] s3 = detect(Image.FromFile(@"trn\SpellIcon_13.png"));
            double[] s4 = detect(Image.FromFile(@"src\DK\BDK_2.png"));
            double[] s5 = detect(Image.FromFile(@"src\DK\BDK_3.png"));
            double[] s6 = detect(Image.FromFile(@"src\DK\BDK_4.png"));
            double[] s7 = detect(Image.FromFile(@"src\DK\BDK_5.png"));
            double[] s8 = detect(Image.FromFile(@"src\DK\BDK_g.png"));
            double[] s9 = detect(Image.FromFile(@"trn\SpellIcon_10.png"));
            double[] s10 = detect(Image.FromFile(@"trn\SpellIcon_14.png"));
            double[] s11 = detect(Image.FromFile(@"trn\SpellIcon_15.png"));
            double[] s12 = detect(Image.FromFile(@"trn\SpellIcon_17.png"));
            double dist = HSVLib.ngdistance(s1, s2);
            double dist2 = HSVLib.ngdistance(s3, s4);
            double dist3 = HSVLib.ngdistance(s1, s3);
            double dist4 = HSVLib.ngdistance(s1, s4);
            double dist5 = HSVLib.ngdistance(s1, s5);
            double dist6 = HSVLib.ngdistance(s1, s6);
            double dist7 = HSVLib.ngdistance(s1, s7);
            double dist8 = HSVLib.ngdistance(s1, s8);
            double dist9 = HSVLib.ngdistance(s1, s9);
            double dist10 = HSVLib.ngdistance(s1, s10);
            double dist11 = HSVLib.ngdistance(s1, s11);
            double dist12 = HSVLib.ngdistance(s1, s12);
            double dist13 = HSVLib.ngdistance(s2, s9);
             */
            /*
            sr = new double[6][];
            
            sr[0] = detect(Image.FromFile(@"C:\Users\Nostalgia\Documents\visual studio 2012\Projects\src\S1.bmp"));
            sr[1] = detect(Image.FromFile(@"C:\Users\Nostalgia\Documents\visual studio 2012\Projects\src\S2.bmp"));
            sr[2] = detect(Image.FromFile(@"C:\Users\Nostalgia\Documents\visual studio 2012\Projects\src\S3.bmp"));
            sr[3] = detect(Image.FromFile(@"C:\Users\Nostalgia\Documents\visual studio 2012\Projects\src\S4.bmp"));
            sr[4] = detect(Image.FromFile(@"C:\Users\Nostalgia\Documents\visual studio 2012\Projects\src\S5.bmp"));
            sr[5] = detect(Image.FromFile(@"C:\Users\Nostalgia\Documents\visual studio 2012\Projects\src\S6.bmp"));
             */
            /*
            sr = new double[keyc][];
            sr[0] = detect(Image.FromFile(@"C:\Users\Nostalgia\Documents\visual studio 2012\Projects\src\LR1.bmp"));
            sr[1] = detect(Image.FromFile(@"C:\Users\Nostalgia\Documents\visual studio 2012\Projects\src\LR2.bmp"));
            sr[2] = detect(Image.FromFile(@"C:\Users\Nostalgia\Documents\visual studio 2012\Projects\src\LR3.bmp"));
            sr[3] = detect(Image.FromFile(@"C:\Users\Nostalgia\Documents\visual studio 2012\Projects\src\LR4.bmp"));
            sr[4] = detect(Image.FromFile(@"C:\Users\Nostalgia\Documents\visual studio 2012\Projects\src\LR5.bmp"));
            sr[5] = detect(Image.FromFile(@"C:\Users\Nostalgia\Documents\visual studio 2012\Projects\src\LRq.bmp"));
            sr[6] = detect(Image.FromFile(@"C:\Users\Nostalgia\Documents\visual studio 2012\Projects\src\LRf.bmp"));
            sr[7] = detect(Image.FromFile(@"C:\Users\Nostalgia\Documents\visual studio 2012\Projects\src\LRv.bmp"));
            srs = detect(Image.FromFile(@"C:\Users\Nostalgia\Documents\visual studio 2012\Projects\src\NT.bmp"));
            */
            //sr = new double[keyc][];
            srlib = new Dictionary<string, List<SpellInfo>>();

            DirectoryInfo d = new DirectoryInfo(@"src");
            FileInfo[] f = d.GetFiles("*.png", SearchOption.AllDirectories);
            IEnumerable<FileInfo> fl = f.Concat(d.GetFiles("*.bmp", SearchOption.AllDirectories));
            
            /*
            foreach (FileInfo fi in fl0)
            {
                double[,] s1 = detect(Image.FromFile(fi.FullName));
                double mindist = 100;
                string target = null;
                foreach (FileInfo fi1 in fl)
                {
                    double[,] s2 = detect(Image.FromFile(fi1.FullName));
                    //Console.WriteLine(fi.Name + " to Ori is:" + HSVLib.ngdistance(s1, s2));
                    if (fi1.Name.Equals("BDK_1.png") && fi.Name.Equals("BDK_1.bmp"))
                    {
                        double dist0;
                    }
                    double dist = HSVLib.ngdistance2(s1, s2);
                    if (dist < mindist)
                    {
                        mindist = dist;
                        target = fi1.Name;
                    }
                }
                Console.WriteLine(fi.Name + " to " + target + " is:" + mindist);
            }*/
            
            foreach (FileInfo fi in fl)
            {
                string si = fi.Name.Substring(0, fi.Name.LastIndexOf('.'));
                if (si.Equals("NT"))
                {
                    nullspell = new SpellInfo();
                    nullspell.key = (char)0;
                    nullspell.image = Image.FromFile(fi.FullName);
                    nullspell.sr = detect(nullspell.image);
                    nullspell.image.Dispose();
                    continue;
                }

                string[] si2 = si.Split(new char[] { '_' });
                SpellInfo sp = new SpellInfo();

                int result;
                if (si2[1].Length == 1)
                {
                    sp.key = si2[1].ToUpper()[0];
                }
                else if (int.TryParse(si2[1], out result))
                {
                    sp.key = (char)result;
                }
                else
                {

                    sp.key = (char)0;
                }
                if (si2[0].Equals("stopcasting"))
                {
                    stopcastingspell = sp;
                    stopcastingspell.image = null;
                    stopcastingspell.sr = null;
                    continue;
                }


                sp.image = Image.FromFile(fi.FullName);
                sp.sr = detect(sp.image);
                sp.image.Dispose();
                if (!srlib.ContainsKey(si2[0]))
                {
                    srlib[si2[0]] = new List<SpellInfo>();
                }
                srlib[si2[0]].Add(sp);
            }


            selectedMastery = "LRBM";
            trainingSpellsHistory = new List<SpellInfo>();


            /*
            sr[0] = detect(Image.FromFile(@"src\LR1.bmp"));
            sr[1] = detect(Image.FromFile(@"src\LR2.bmp"));
            sr[2] = detect(Image.FromFile(@"src\LR3.bmp"));
            sr[3] = detect(Image.FromFile(@"src\LR4.bmp"));
            sr[4] = detect(Image.FromFile(@"src\LR5.bmp"));
            sr[5] = detect(Image.FromFile(@"src\LRq.bmp"));
            sr[6] = detect(Image.FromFile(@"src\LRf.bmp"));
            sr[7] = detect(Image.FromFile(@"src\LRv.bmp"));
            srs = detect(Image.FromFile(@"src\NT.bmp"));


            keysr = new char[keyc];

            keysr[0] = '1';
            keysr[1] = '2';
            keysr[2] = '3';
            keysr[3] = '4';
            keysr[4] = '5';
            keysr[5] = 'Q';
            keysr[6] = 'F';
            keysr[7] = 'V';
             */
        }



        [DllImport("user32.dll")]
        public static extern bool PrintWindow(
            IntPtr hwnd,               // Window to copy,Handle to the window that will be copied.
            IntPtr hdcBlt,             // HDC to print into,Handle to the device context.
            UInt32 nFlags              // Optional flags,Specifies the drawing options. It can be one of the following values.
        );

        [DllImport("user32.dll", EntryPoint = "GetWindowRect")]
        public static extern int GetWindowRect(
            IntPtr hwnd,
            ref Rectangle rect
        );
        [DllImport("user32.dll", EntryPoint = "GetClientRect")]
        public static extern int GetClientRect(
            IntPtr hwnd,
            ref Rectangle rect
        );
        [DllImport("user32", EntryPoint = "ClientToScreen")]
        public static extern int ClientToScreen(
                IntPtr hwnd,
                ref Point lpPoint
        );

        private bool ColorSimilarToColor(Color c1, Color c2)
        {
            double d1;
            d1 = Math.Pow(c1.R - c2.R, 2) + Math.Pow(c1.G - c2.G, 2) + Math.Pow(c1.B - c2.B, 2);
            d1 = Math.Sqrt(d1) / 3.0;
            if (d1 <= 8)
                return true;
            return false;
        }



        private Image getSpellImage(IntPtr hWnd,out int[] controlValues,string preset)
        {
            controlValues = new int[12];

            Rectangle rect = new Rectangle();
            Point p1 = new Point(0,0);
            //获得要截图窗口的矩阵
            GetWindowRect(hWnd, ref rect);
            //GetClientRect(hWnd, ref rect1);
            ClientToScreen(hWnd,ref p1);
            int xoff = p1.X - rect.X, yoff = p1.Y - rect.Y;

            Rectangle targetRect;
            if (preset.Equals("HEDD"))
            {
                targetRect = new Rectangle(268, 81, 32, 32);
            }
            else if (preset.Equals("CLC"))
            {
                targetRect = new Rectangle(400, 238, 46, 46);
            }
            else
            {
                targetRect = new Rectangle(268, 81, 32, 32);
            }

            targetRect.Offset(xoff,yoff);
            Rectangle controlRect = new Rectangle(targetRect.Right, targetRect.Top, 2, 2);
//            Rectangle pRect = Screen.PrimaryScreen.Bounds;
//            if (rect.Width > 0 && rect.Height > 0 && (rect.Width < pRect.Width || rect.Height < pRect.Height)) {
//               targetRect.Offset(
//            targetRect.Offset(rect.Location);

            //根据要截图的窗口的大小创建位图
            Image myImage = new Bitmap(rect.Width, rect.Height);
            Image targetImage = new Bitmap(targetRect.Width, targetRect.Height);
            Bitmap controlImage = new Bitmap(controlRect.Width,controlRect.Height);

            Graphics myGraphics = Graphics.FromImage(myImage);
            Graphics targetGraphics = Graphics.FromImage(targetImage);
            Graphics controlGraphics = Graphics.FromImage(controlImage);
            //截图
            bool ret = PrintWindow(hWnd, myGraphics.GetHdc(), 0);

            myGraphics.ReleaseHdc();
            targetGraphics.DrawImage(myImage, 0, 0, targetRect, GraphicsUnit.Pixel);
            //myImage.Save(@"C:\Users\Nostalgia\Desktop\full.bmp");
            //targetImage.Save(@"C:\Users\Nostalgia\Desktop\test.bmp");
            
            for (int i = 0; i < controlValues.Length / 2; i++)
            {
                controlValues[i * 2] = 0xcfcfcf;
                controlValues[i * 2 + 1] = 0xcfcfcf;
                controlGraphics.DrawImage(myImage, 0, 0, controlRect, GraphicsUnit.Pixel);
                if (this.ColorSimilarToColor(controlImage.GetPixel(0, 0), Color.Black) && this.ColorSimilarToColor(controlImage.GetPixel(1, 1), Color.White))
                {
                    controlValues[i*2] = controlImage.GetPixel(1, 0).ToArgb();
                    controlValues[i * 2 + 1] = controlImage.GetPixel(0, 1).ToArgb();
                }
                controlRect.Y += controlRect.Height;
            }


            myGraphics.Dispose();
            myImage.Dispose();
            targetGraphics.Dispose();
            controlGraphics.Dispose();
            controlImage.Dispose();

            return targetImage;
        }
        
        public SpellInfo run(IntPtr hWnd, string preset, out string error)
        {
            int[] controlValues;
            Image targetImage = getSpellImage(hWnd,out controlValues,preset);
            error = null;

            if (preset.Equals("HEDD") && ((this.ColorSimilarToColor(Color.FromArgb(controlValues[0]), Color.Red) && this.ColorSimilarToColor(Color.FromArgb(controlValues[1]), Color.Red)) || controlValues[0] == 0xcfcfcf))
            {
                targetImage.Dispose();
                error = controlValues[0] == 0xcfcfcf ? "HEDD Not Found" : "Chat Dialog Opened";
                return null;
            }
            if (preset.Equals("HEDD") && controlValues[4] != 0xcfcfcf && controlValues[4] != 0)
            {
                string talentname;
                talentname = new string(new char[]{(char)Color.FromArgb(controlValues[4]).R , (char)Color.FromArgb(controlValues[4]).G , (char)Color.FromArgb(controlValues[5]).R , (char)Color.FromArgb(controlValues[5]).G});
                talentname = talentname.Trim().Replace("\0","");
                //Console.WriteLine(talentname);
                if (srlib.ContainsKey(talentname) && selectedMastery != talentname)
                {
                    selectedMastery = talentname;
                }
            }


            SpellInfo i = detect_hedd(targetImage);
            if (i == null || i.key == 0)
            {
                error = "Spell Not Found";
            }
            else if (preset.Equals("HEDD") && (this.ColorSimilarToColor(Color.FromArgb(controlValues[8]), Color.White) && this.ColorSimilarToColor(Color.FromArgb(controlValues[9]), Color.White)) ) {
                i.stopcasting = true;
			}
            /*
            int tar = controlValues[6] & 0x000000ff;
            if (preset.Equals("HEDD") && controlValues[6] != 0xcfcfcf && tar >= 0 && tar <= 40 && (0x0ffff & (controlValues[6] >> 8)) == 0xffff)
            {
                if (i == null)
                    i = new SpellInfo();
                i.target = tar;
            }*/
            //targetImage.Save(@"PrintScreen" + ".bmp");
            targetImage.Dispose();
            return i;
             
        }

        public void trainingSpells(IntPtr hWnd,string preset)
        {
            int[] controlValues;
            Image targetImage = getSpellImage(hWnd,out controlValues,preset);
            double[,] sr = detect(targetImage);
            //double d0,d1,d2;
            foreach (SpellInfo si in trainingSpellsHistory)
            {
                /*
                d0 = Math.Abs(si.sr[0] - sr[0]) / si.sr[0];
                d1 = Math.Abs(si.sr[1] - sr[1]) / si.sr[1];
                d2 = Math.Abs(si.sr[2] - sr[2]) / si.sr[2];
                if (d0 < 0.05 && d1 < 0.05 && d2 < 0.05)
                {
                    return;
                }
                 */
                double dist = HSVLib.ngdistance2(si.sr, sr);
                if (dist < 2)
                {
                    return;
                }
            }
            SpellInfo nsi = new SpellInfo((char)0, targetImage, sr);
            trainingSpellsHistory.Add(nsi);
            Directory.CreateDirectory("trn");
            targetImage.Save(@"trn\SpellIcon_" + trainingSpellsHistory.Count + ".png");
            targetImage.Dispose();
        }

        public void clearTrainingHistory()
        {
            trainingSpellsHistory.Clear();
        }

        private SpellInfo detect_hedd(Image targetImage)
        {
            double[,] dr = detect(targetImage);
            SpellInfo ri = nullspell;
            double mind = HSVLib.ngdistance2(dr, nullspell.sr);// (Math.Abs(nullspell.sr[0] - dr[0]) / nullspell.sr[0]) + (Math.Abs(nullspell.sr[1] - dr[1]) / nullspell.sr[1] + Math.Abs(nullspell.sr[2] - dr[2]) / nullspell.sr[2]);
            /*
            double d0, d1, d2;
            foreach (SpellInfo si in srlib[selectedMastery])
            {
                d0 = Math.Abs(si.sr[0] - dr[0]) / si.sr[0];
                d1 = Math.Abs(si.sr[1] - dr[1]) / si.sr[1];
                d2 = Math.Abs(si.sr[2] - dr[2]) / si.sr[2];

                if (d0 < 0.1 && d1 < 0.1 && d2 < 0.1)
                {
                    if (d0 + d1 + d2 < mind)
                    {
                        mind = d0 + d1 + d2;
                        ri = si;
                    }
                }
            }
             */
            foreach (SpellInfo si in srlib[selectedMastery])
            {
                double dist = HSVLib.ngdistance2(si.sr, dr);
                if (dist <= 12 && dist < mind)
                {
                    mind = dist;
                    ri = si;
                }
            }
            if (ri != null)
            {
                return new SpellInfo(ri);
            }
            return null;
        }

        /*
        private int detect_clc(Image targetImage)
        {
            double[] dr = detect(targetImage);
            int i;
            for (i = 0; i < keyc; i++)
            {
                if (Math.Abs(sr[i][1] - dr[1]) / sr[i][1] < 0.3 && Math.Abs(sr[i][2] - dr[2]) / sr[i][2] < 0.3)
                {
                    Console.WriteLine("Press " + keysr[i]);
                    break;
                }
            }
            if (6 == i)
            {
                Console.WriteLine("Pass");
                i = -1;
            }
            return i;
        }
        */
        private double[] detect1(Image image)
        {
            Bitmap b = new Bitmap(image);
            double sr = 0, sg = 0, sb = 0;
            for (int i = 0; i < b.Width; i++)
            {
                for (int j = 0; j < b.Height; j++)
                {
                    Color c = b.GetPixel(i, j);
                    sr += c.R;
                    sg += (c.G + 1.0) / (c.R + 1.0);
                    sb += (c.B + 1.0) / (c.R + 1.0);
                }
            }
            sr /= b.Width * b.Height;
            sg /= b.Width * b.Height;
            sb /= b.Width * b.Height;
            return new double[] { sr, sg, sb };
        }
        
        private double[] detect_old(Image image)
        {
            Bitmap b = new Bitmap(image);
            double sr = 0, sg = 0, sb = 0;
            int cut = 2;
            for (int i = cut; i < b.Width - cut; i++)
            {
                for (int j = cut; j < b.Height - cut; j++)
                {
                    Color c = b.GetPixel(i, j);
                    sr += c.R;
                    sg += c.G;
                    sb += c.B;
                }
            }
            int pcount = (b.Width - cut*2) * (b.Height - cut*2);
            sr /= pcount;
            sg /= pcount; //* sr;
            sb /= pcount; //* sr; 
            b.Dispose();
            return new double[] { sr, sg, sb };
        }
        
        private double[,] detect(Image image)
        {
            Bitmap b = new Bitmap(image);
            int div = 32;
            double[,] res = new double[3,div];
            /*
            int[] histogram = new int[256];
            int[] histogram2 = new int[256];
            int[] histogram3 = new int[256];
            int[] histogram4 = new int[256];
             */
            int cut = 4;
            double pcount = (b.Width - cut * 2) * (b.Height - cut * 2);
            for (int i = cut; i < b.Width - cut; i++)
            {
                for (int j = cut; j < b.Height - cut; j++)
                {
                    Color c = b.GetPixel(i, j);
                    //histogram[(int)Math.Floor(HSVLib.rgb2gray(c.R, c.G, c.B))]++;
                    /*
                    histogram2[c.R]++;
                    histogram3[c.G]++;
                    histogram4[c.B]++;
                     */

                    res[0, (int)Math.Floor(c.R / (double)div)] ++;
                    res[1, (int)Math.Floor(c.G / (double)div)] ++;
                    res[2, (int)Math.Floor(c.B / (double)div)] ++;
                    //int g = (int)(HSVLib.rgb2gray(c.R, c.G, c.B) / 16.0);//HSVLib.hsv2g(HSVLib.rgb2hsv(c.R, c.G, c.B));
                    //res[g] += 1.0 / pcount;
                }
            }
            for (int i = 0; i < res.GetLength(1); i++)
            {
                res[0, i] *= (900.0 / pcount);
                res[1, i] *= (900.0 / pcount);
                res[2, i] *= (900.0 / pcount);
            }
            /*
            int[] newhg = histogram;// HSVLib.histogramEqualization(histogram, (int)pcount);
            int[] newhg2 = histogram2;//HSVLib.histogramEqualization(histogram2, (int)pcount);
            int[] newhg3 = histogram3;//HSVLib.histogramEqualization(histogram3, (int)pcount);
            int[] newhg4 = histogram4;//HSVLib.histogramEqualization(histogram4, (int)pcount);
            for (int i = 0; i < newhg.Length; i++)
            {
                res[0, (int)Math.Floor(i / 16.0)] += newhg2[i];
                res[1, (int)Math.Floor(i / 16.0)] += newhg3[i];
                res[2, (int)Math.Floor(i / 16.0)] += newhg4[i];
            }
             */
            b.Dispose();
            return res;
        }
        

        public Dictionary<string, List<SpellInfo>> srlib;
        /*
        private double[][] sr;
        private double[] srs;
        public char[] keysr;
        private const int keyc = 8;
         * */
        private SpellInfo nullspell;
        public SpellInfo stopcastingspell;
        public string selectedMastery;
        
        private List<SpellInfo> trainingSpellsHistory;
    }

    public class SpellInfo
    {
        public SpellInfo()
        {
            this.target = 255;
            this.key = (char)0;
            this.stopcasting = false;
			this.nogcd = false;
        }

        public SpellInfo(SpellInfo si)
        {
            this.key = si.key;
            this.image = si.image;
            this.sr = si.sr;
            this.needMouse = si.needMouse;
            this.target = si.target;
            this.stopcasting = si.stopcasting;
			this.nogcd = si.nogcd;
        }

        public SpellInfo(char key, Image image, double[,] sr) {
            this.key = key;
            this.image = image;
            this.sr = sr;
            needMouse = false;
            target = 255;
            stopcasting = false;
			nogcd = false;
        }

        public char key;
        public Image image;
        public double[,] sr;
        public bool needMouse;
        public int target;
        public bool stopcasting;
        public bool nogcd;
    }

    class HSVLib
    {
        public static double[] rgb2hsv(double r, double g, double b)
        {
            double h = 0, s = 0, v = 0;
            double max = r, min = r;
            //if (r > 1) 
            r = r / 255;
            //if (g > 1) 
            g = g / 255;
            //if (b > 1) 
            b = b / 255;
            max = Math.Max(r, Math.Max(g, b));
            min = Math.Min(r, Math.Min(g, b));
            v = max;
            if (max == 0)
            {
                s = 0;
            }
            else
            {
                s = (max - min) / max;
            }
            if (max == min) { 
                h = 0;
            } else {
                if (r == max) { h = (g - b) / (max - min); }
                if (g == max) { h = 2 + (b - r) / (max - min); } 
                if (b == max) { h = 4 + (r - g) / (max - min); } 
            } 
            h = h * 60; 
            if (h < 0) 
            { 
                h = h + 360; 
            };
            return new double[3]{h,s,v};
        }
        public static int hsv2g(double[] hsv)
        {
            double g=0;
            g += Math.Floor(hsv[0] / 360.0 * qh) * qs * qv;
            g += Math.Floor(hsv[1] / qs) * qv;
            g += Math.Floor(hsv[2] / qv);
            return (int)g;
        }
        public static double rgb2gray(double r, double g, double b)
        {
            double gray = (r * 30.0 + g * 59.0 + b * 11.0 + 50.0) / 100.0;
            return gray;
        }

        public static int gmax()
        {
            return (int)(qh * qs * qv);
        }

        public static double ngdistance(double[] v1, double[] v2) {
            double dist = 0;
            for (int i = 0; i < v1.Length; i++)
            {
                dist += (v1[i] - v2[i]) * (v1[i] - v2[i]);
            }
            dist = Math.Sqrt(dist) / v1.Length;
            return dist;
        }


        public static double ngdistance2(double[,] v1, double[,] v2)
        {
            double[] dist = new double[v1.GetLength(0)];
            double res = 1;
            for (int i = 0; i < v1.GetLength(1); i++)
            {
                for (int k = 0; k < v1.GetLength(0); k++)
                {
                    dist[k] += (v1[k, i] - v2[k, i]) * (v1[k, i] - v2[k, i]);
                }
            }

            for (int k = 0; k < v1.GetLength(0); k++)
            {
                res *= ((Math.Sqrt(dist[k]) / v1.GetLength(1))+1);
            }
            return res;
        }

        public static int[] histogramEqualization(int[] histogram, int count)
        {
            double[] p = new double[histogram.Length];
            double[] c = new double[histogram.Length];

            int[] res = new int[histogram.Length];

            for (int i = 0; i < histogram.Length; i++)
            {
                p[i] = 0;
                c[i] = 0;
                res[i] = 0;
            }
            for (int i = 0; i < histogram.Length; i++)
            {
                p[i] = (double)histogram[i] / count;
                for (int j = 0; j <= i; j++)
                {
                    c[i] += p[j];
                }
                int newpos = (int)Math.Floor((histogram.Length - 1) * c[i] + 0.5);
                res[newpos] += histogram[i];
            }
            return res;
        }

        const double qh = 9, qs = 4, qv = 4;
    }

}
